<?php


namespace app\wx_pay\controller;
use think\facade\Config;
use think\facade\Db;
class JsApiPayV2
{
	/*
	--
	-- 表的结构 `sign_order`
	--

	CREATE TABLE `sign_order` (
	  `id` int(11) NOT NULL,
	  `out_trade_no` varchar(32) DEFAULT NULL COMMENT '订单号',
	  `uid` int(11) DEFAULT '0' COMMENT '用户id',
	  `ispay` tinyint(4) DEFAULT '0' COMMENT '是否支付成功',
	  `pay_time` datetime DEFAULT NULL COMMENT '支付时间',
	  `pay_price` decimal(10,2) DEFAULT NULL,
	  `add_time` datetime DEFAULT NULL,
	  `num` varchar(100) DEFAULT NULL COMMENT '报名人数',
	  `danwei` varchar(100) DEFAULT NULL COMMENT '单位',
	  `emailaddress` varchar(255) DEFAULT NULL COMMENT '邮寄地址',
	  `shibiehao` varchar(255) DEFAULT NULL COMMENT '纳税人识别号',
	  `fapiao` varchar(50) DEFAULT NULL COMMENT '发票领取方式',
	  `beizhu` text COMMENT '备注',
	  `xinxiang` varchar(255) DEFAULT NULL COMMENT '收票信箱'
	) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

	--
	-- 表的索引 `sign_order`
	--
	ALTER TABLE `sign_order`
	  ADD PRIMARY KEY (`id`),
	  ADD KEY `u_id` (`uid`) USING BTREE;
	--
	-- 使用表AUTO_INCREMENT `sign_order`
	--
	ALTER TABLE `sign_order`
	  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;	
	
	*/
	
    //JSAPI V2支付接口
    //----------------------微信支付----------------------------
    //微信支付 订单号、openid、金额、回调
    public function wx_pay($appid,$out_trade_no, $openid, $money, $back_url)
    {
        $nonce_str = $this->rand_code();//随机字符串
        $data['appid'] = $appid;
        $data['mch_id'] =config('wx')['mch_id'];
        $data['body'] = "支付";
        $data['spbill_create_ip'] = $_SERVER["REMOTE_ADDR"];
//         $money = 0.01;
        $data['total_fee'] = $money * 100;//total_fee 单位：分
        $data['out_trade_no'] = $out_trade_no;
        $data['nonce_str'] = $nonce_str;
        $data['notify_url'] = $back_url;

        $data['trade_type'] = 'JSAPI';
        $data['openid'] = $openid;
        // var_dump($data);
        // exit();
        $data['sign'] = $this->getSign($data);
        $xml = $this->ToXml($data);
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $res_tmp = $this->req_Post($url, $xml);
        // var_dump($data['sign']);
        // return json(array('code' => -1, 'msg' => $res_tmp));
        if ($res_tmp) {
            $resdata = $this->FromXml($res_tmp);
            // var_dump($resdata);
            if ($resdata['result_code']!='SUCCESS') {
                return false;
            } else {
                $pdata['appId'] = $appid;
                $pdata['timeStamp'] = time() . '';
                $pdata['nonceStr'] = $this->rand_code();
                $pdata['package'] = 'prepay_id=' . $resdata['prepay_id'];
                $pdata['signType'] = 'MD5';
                $pdata['sign'] = $this->getSign($pdata);
                $pdata['prepay_id'] = $resdata['prepay_id'];
                return $pdata;
            }
        } else {
            return false;
        }
    }
    /**
     * 微信退款
     * $appid appid
     * $out_trade_no 订单号
     * $money 退款金额
     */
    public function refund($appid,$out_trade_no, $money)
    {
        $nonce_str = $this->rand_code();//随机字符串
        $data['appid'] = $appid;//1
        $data['mch_id'] = config('wx')['mch_id'];//1
        $data['total_fee'] = $money * 100;//1
        $data['refund_fee'] = $money * 100;//1
        $data['out_trade_no'] = $out_trade_no;
        $data['out_refund_no'] = md5(date("YmdHis")."out_refund_no");
        $data['nonce_str'] = $nonce_str;
        foreach ($data as $tmp) {
            if (empty($tmp)) {
                return false;
            }
        }
        $data['sign'] = $this->getSign($data);
        $xml = $this->ToXml($data);
        $url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
        $res_tmp = $this->req_Posts($url, $xml);
        // var_dump($res_tmp);
        if ($res_tmp) {
            $resdata = $this->FromXml($res_tmp);
            if ($resdata['result_code'] == 'SUCCESS') {
                //return $resdata;
                return $resdata;
            } else {
                return $resdata;
            }
        } else {
            return false;
        }
    }
    //支付成功回调的方法
    public function paySuccess()
    {
        $resdata=$this->paynotifyurl();
        // $resdata['out_trade_no']='210608161609100000111';
        if ($resdata && $resdata['out_trade_no']) {
            $resupdate=Db::table("sign_order")->where('out_trade_no', $resdata['out_trade_no'])->where("ispay=0")
                ->update(array("ispay"=>"1","pay_time" => date('Y-m-d H:i:s')));
        }
    }

    public function req_Post($url, $udata)
    {
        $timeout = 5;
        $con = curl_init();
        curl_setopt($con, CURLOPT_URL, $url);
        curl_setopt($con, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($con, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($con, CURLOPT_POST, true);
        curl_setopt($con, CURLOPT_POSTFIELDS, $udata);
        curl_setopt($con, CURLOPT_HEADER, false);
        curl_setopt($con, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($con, CURLOPT_TIMEOUT, (int)$timeout);
        $p_res = curl_exec($con);
        curl_close($con);
        if ($p_res) {
            return $p_res;
        } else {
            return false;
        }
    }

    private function req_Posts($url, $udata)
    {
        $file_path = ROOT_PATH . "config" . DS . "cert" . DS;
        $key_path = "apiclient_key.pem";
        $cret_path = "apiclient_cert.pem";
        if (empty($url)) {
            return false;
        }
        $timeout = 5;
        $con = curl_init();
        curl_setopt($con, CURLOPT_URL, $url);
        curl_setopt($con, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($con, CURLOPT_SSL_VERIFYHOST, false);

        curl_setopt($con, CURLOPT_SSLCERTTYPE, 'pem');
        curl_setopt($con, CURLOPT_SSLCERT, $file_path . $cret_path);
        curl_setopt($con, CURLOPT_SSLKEYTYPE, 'pem');
        curl_setopt($con, CURLOPT_SSLKEY, $file_path . $key_path);

        curl_setopt($con, CURLOPT_POST, true);
        curl_setopt($con, CURLOPT_POSTFIELDS, $udata);
        curl_setopt($con, CURLOPT_HEADER, false);
        curl_setopt($con, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($con, CURLOPT_TIMEOUT, (int)$timeout);
        $p_res = curl_exec($con);
        curl_close($con);
        return $p_res;
    }

    //php发送get请求
    private function req_Get($curl)
    {
        if ($curl == "") {
            return false;
        }
        $timeout = 5;
        $con = curl_init();
        curl_setopt($con, CURLOPT_URL, $curl);
        curl_setopt($con, CURLOPT_HEADER, false);
        curl_setopt($con, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($con, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($con, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($con, CURLOPT_TIMEOUT, (int)$timeout);
        $c_res = curl_exec($con);
        curl_close($con);
        if ($c_res) {
            return $c_res;
        } else {
            return false;
        }
    }

    private function paynotifyurl()
    {
        $xml = file_get_contents('php://input');
        if (empty($xml)) {
            return false;
        }
        $resdata = $this->FromXml($xml);
        if (empty($resdata)) {
            return false;
        }
        $sign_tmp = $resdata['sign'];
        unset($resdata['sign']);
        $checkSign = $this->getSign($resdata);
        if ($checkSign == $sign_tmp) {
            if ($resdata['return_code'] == 'SUCCESS') {
                echo "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
                return $resdata;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    //签名
    private function getSign($sig_data)
    {
        ksort($sig_data);
        foreach ($sig_data as $key => $s_tmp) {
            if (!empty($s_tmp)) {
                $newArr[] = $key . '=' . $s_tmp;
            }
        }
        $str_sign = implode("&", $newArr);
        $stringSignTemp = $str_sign . "&key=" .config('wx')['app_key2'];
        $stringSignTemp = MD5($stringSignTemp);
        $sign = strtoupper($stringSignTemp);
        return $sign;
    }

    //数组转xml
    public function ToXml($data = array())
    {
        if (!is_array($data) || count($data) <= 0) {
            return false;
        }
        $xml = "<xml>";
        foreach ($data as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
                //$xml.="<".$key.">".$val."</".$key.">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    //xml转数组
    public function FromXml($xml)
    {
        if (!$xml) {
            return false;
        }
        libxml_disable_entity_loader(true);
        $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $data;
    }

    //获取随机字符串
    private function rand_code()
    {
        $str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $str = str_shuffle($str);
        $str = substr($str, 0, 32);
        return $str;
    }

    protected function curlmulti($host)
    {
        if (empty($host)) {
            return false;
        }
        $ch1 = curl_init();
        curl_setopt($ch1, CURLOPT_URL, $host);
        curl_setopt($ch1, CURLOPT_HEADER, false);
        curl_setopt($ch1, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch1, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch1, CURLOPT_TIMEOUT, 10);

        $cmh = curl_multi_init();
        curl_multi_add_handle($cmh, $ch1);
        curl_multi_exec($cmh, $active);
        curl_multi_remove_handle($cmh, $ch1);
        curl_multi_close($cmh);
        var_dump($active);
        return $active;
    }
}